﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.Rendering;


namespace YYPostProcessing
{
    public class YYBloom : YYPostProcessEffectRenderer
    {
        //internal static readonly int MainTex = Shader.PropertyToID("_MainTex");

        //[Range(0,10)]
        //public float threshold = 1.0f;

        [Range(0, 5)]
        public float bloomThreshold = 1.0f;

        [Range(0, 1)]
        public float softKnee = 0.5f;

        //[Range(-1f,1f)]
        private float anamorphicRatio = 0f;   //  宽高比

        //为了性能添加的参数 
        [Range(1,3)]
        public int m_iterations = 3;

        [Range(1, 10)]
        public int m_sampleScale = 2;
        //

        public Vector4 m_testParam = new Vector4(1, 1, 1, 1);

        // [down,up]
        Level[] m_Pyramid;
        const int k_MaxPyramidSize = 8; // Just to make sure we handle 64k screens... Future-proof!
        struct Level
        {
            internal int down;
            internal int up;
        }

        private void Awake()
        {
            m_Pyramid = new Level[k_MaxPyramidSize];

            for (int i = 0; i < k_MaxPyramidSize; i++)
            {
                m_Pyramid[i] = new Level
                {
                    down = Shader.PropertyToID("_BloomMipDown" + i),
                    up = Shader.PropertyToID("_BloomMipUp" + i)
                };
            }
        }

      

        public override void Render(YYPostProcessRenderContext context)
        
        {
            var cmd = context.command;

            cmd.BeginSample("BloomPyramid");

            //var sheet = context.propertySheets.Get(Shader.Find("YY/PostProcess/YYBloom"));
            var sheet = context.propertySheets.Get(context.resources.shaders.bloom);

            float ratio = Mathf.Clamp(anamorphicRatio, -1, 1);
            float rw = ratio < 0 ? -ratio : 0f;
            float rh = ratio > 0 ? ratio : 0f;

            int tw = Mathf.FloorToInt(context.screenWidth / (2f - rw));
            int th = Mathf.FloorToInt(context.screenHeight / (2f - rh));
            //int tw = context.screenWidth;// Mathf.FloorToInt(context.screenWidth / (2f - rw));
            //int th = context.screenHeight;// Mathf.FloorToInt(context.screenHeight / (2f - rh));
            int tw_stereo = tw;

            float sampleScale = m_sampleScale;// 2.0f;
            sheet.properties.SetFloat(YYShaderIDs.SampleScale, sampleScale);

            // Prefiltering parameters
            float lthresh = Mathf.GammaToLinearSpace(bloomThreshold);
            float knee = lthresh * softKnee + 1e-5f;
            var threshold = new Vector4(lthresh, lthresh - knee, knee * 2f, 0.25f / knee);
            sheet.properties.SetVector(YYShaderIDs.Threshold, threshold);

            sheet.properties.SetVector(YYShaderIDs.TestParam, m_testParam);

            var lastDown = context.source;
            int iterations = m_iterations;
            for (int i = 0; i < iterations; i++)
            {
                int mipDown = m_Pyramid[i].down;
                int mipUp = m_Pyramid[i].up;
                int pass = i == 0 ? 1 : 2;

                //cmd.GetTemporaryRT(mipDown, tw, th);
                //cmd.GetTemporaryRT(mipUp, tw, th);
                context.GetScreenSpaceTemporaryRT(cmd, mipDown, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
                context.GetScreenSpaceTemporaryRT(cmd, mipUp, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
                
                cmd.BlitFullscreenTriangle(lastDown, mipDown, sheet, pass);

                lastDown = mipDown;

                tw_stereo = tw_stereo / 2;
                tw_stereo = Mathf.Max(tw_stereo, 1);
                th = Mathf.Max(th / 2, 1);
            }

            int lastUp = m_Pyramid[iterations - 1].down;
            for (int i = iterations - 2; i >= 0; i--)
            {
                int mipDown = m_Pyramid[i].down;
                int mipUp = m_Pyramid[i].up;

                cmd.SetGlobalTexture(YYShaderIDs.BloomTex, mipDown);
                cmd.BlitFullscreenTriangle(lastUp, mipUp, sheet, 3);
                lastUp = mipUp;
            }



            cmd.SetGlobalTexture(YYShaderIDs.BloomTex, lastUp);

            ////cmd.Blit(lastUp, BuiltinRenderTextureType.CameraTarget, sheet.material, 0);

            //cmd.Blit(lastUp, BuiltinRenderTextureType.CameraTarget);


            // Cleanup
            for (int i = 0; i < iterations; i++)
            {
                if (m_Pyramid[i].down != lastUp)
                    cmd.ReleaseTemporaryRT(m_Pyramid[i].down);
                if (m_Pyramid[i].up != lastUp)
                    cmd.ReleaseTemporaryRT(m_Pyramid[i].up);
            }

            cmd.EndSample("BloomPyramid");

        }
    }
}
